#include "ReLog.hpp"
#include <iostream>
#include <string>
#include <cstring>
#include <pthread.h>

#include <signal.h>
#include <unistd.h>

#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h> //!

using namespace std;

class TcpServer;

class ThreadData
{
public:
    uint16_t clientPort_;
    std::string clientIp_;
    int sock_;
    TcpServer *this_;

public:
    ThreadData(uint16_t port, std::string ip, int sock, TcpServer *ts)
        : clientPort_(port), clientIp_(ip), sock_(sock), this_(ts)
    {
    }
};

class TcpServer
{
public:
    TcpServer(uint16_t port, const std::string &ip = "")
        : port_(port),
          ip_(ip),
          listensocket_(-1){};
    ~TcpServer(){};

public:
    void init()
    {
        // 1. 创建socket
        listensocket_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listensocket_ < 0)
        {
            logMessage(FATAL, "socket:%s", strerror(errno));
            exit(1);
        }
        logMessage(FATAL, "socket:%s,%d", strerror(errno), listensocket_);
        // 设置套接字选项，使其可以重用地址
        int opt = 1;
        if (setsockopt(listensocket_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1)
        {
            perror("setsockopt");
            exit(1);
        }

        // 2. bind绑定
        // 填充服务器信息
        struct sockaddr_in local; // 用户栈
        bzero(&local, sizeof local);
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        ip_.empty() ? (local.sin_addr.s_addr = INADDR_ANY) : (inet_aton(ip_.c_str(), &local.sin_addr));
        // 本地socket信息，写入sock_对应的内核区域
        if (bind(listensocket_, (const sockaddr *)&local, sizeof(local)) == -1)
        {
            logMessage(FATAL, "bind listen_socket fail");
            exit(2);
        }
        logMessage(DEBUG, "bind listen_socket success");

        // 3. 监听socket
        if (listen(listensocket_, 5) < 0)
        {
            logMessage(FATAL, "listen fail");
            exit(2);
        }
        logMessage(DEBUG, "start listen");
    }

    void loop()
    {
        signal(SIGCHLD, SIG_IGN);
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);

            int serverSocket = accept(listensocket_, (struct sockaddr *)&peer, &len);
            if (serverSocket < 0)
            {
                logMessage(WARINING, "accept:%s[%d]", strerror(errno), serverSocket);
                continue;
            }
            logMessage(DEBUG, "accept success");
            // 获取客户端基本信息
            uint16_t peerPort = ntohs(peer.sin_port);
            std::string peerIp = inet_ntoa(peer.sin_addr);

            logMessage(DEBUG, "accept: %s | %s[%d],socket fd: %d",
                       strerror(errno), peerIp.c_str(), peerPort, serverSocket);
            // 处理客户请求
            ThreadData *td = new ThreadData(peerPort, peerIp, serverSocket, this);
            pthread_t tid;
            pthread_create(&tid, nullptr, threadRoutine, (void *)td);
        }
    }

    // 处理客户端请求
    static void *threadRoutine(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        td->this_->Server(td->sock_, td->clientIp_, td->clientPort_);
        // std::cout<<"server...."<<std::endl;
        delete td;
        return nullptr;
    }

// 服务器提供的服务                //1 人工 2 AI 3 看流星雨
#define BUFFER_SIZE 1204
    void Server(int sock, const std::string &clientIp, uint16_t clientPort)
    {
        // std::cout << "曦宝输入1，提供人工服务。输入2，提供AI服务(找AI去玩)，输入3，看流星雨。输入4，退出。" << std::endl;
        //usleep(3000);
        char inbuffer[BUFFER_SIZE];

        char sendbuf[256], recvbuf[256];

        ssize_t s = read(sock, inbuffer, sizeof(inbuffer) - 1); // 我们认为我们读到的都是字符串
        cout<<inbuffer<<endl;
        while (true)
        {
            if (strcasecmp(inbuffer, "4") == 0)
            {
                logMessage(DEBUG, "client quit -- %s[%d]", clientIp.c_str(), clientPort);
                break;
            }
            else if (strcasecmp(inbuffer, "1") == 0)
            {
                cout << "选择人工" << endl;
                while (true)
                {
                    cout << "林林#";
                    cin >> sendbuf;
                    send(sock, sendbuf, strlen(sendbuf) + 1, 0);
                    if (recv(sock, recvbuf, 256, 0) > 0)
                    {
                        if(recvbuf=="4") goto FLG;//退出
                        std::cout << "曦宝#" << recvbuf << std::endl;
                    }
                    else
                    {
                        std::cout << "曦宝 has close" << std::endl;
                        goto FLG;
                    }
                }
            }
            else if (strcasecmp(inbuffer, "2") == 0)
            {
                cout << "选择AI" << endl;
                while (true)
                {
                    cout << "AI#";
                    cin >> sendbuf;
                    send(sock, sendbuf, strlen(sendbuf) + 1, 0);
                    if (recv(sock, recvbuf, 256, 0) > 0)
                    {
                        if(recvbuf=="4") goto FLG;//退出
                        std::cout << "曦宝#" << recvbuf << std::endl;
                    }
                    else
                    {
                        std::cout << "曦宝 has close" << std::endl;
                        goto FLG;
                    }
                }
            }
            else if (strcasecmp(inbuffer, "3") == 0)
            {
            }
            else
            {
                std::cout << "宝宝别输错啦~,是 1 2 3 4哦" << std::endl;
            }
        }
FLG:
        // while (true)
        // {

        //     ssize_t s = read(sock, inbuffer, sizeof(inbuffer) - 1); // 我们认为我们读到的都是字符串
        //     if (s > 0)
        //     {
        //         // read success
        //         inbuffer[s] = '\0';
        //         // logMessage(DEBUG, "trans before: %s[%d]>>> %s", clientIp.c_str(), clientPort, inbuffer);
        //         //  // 可以进行大小写转化了
        //         //  for(int i = 0; i < s; i++)
        //         //  {
        //         //      if(isalpha(inbuffer[i]) && islower(inbuffer[i]))
        //         //          inbuffer[i] = toupper(inbuffer[i]);
        //         //  }
        //         //  logMessage(DEBUG, "trans after: %s[%d]>>> %s", clientIp.c_str(), clientPort, inbuffer);
        //         // write(sock, inbuffer, strlen(inbuffer));
        //     }
        //     else if (s == 0)
        //     {
        //         // pipe: 读端一直在读，写端不写了，并且关闭了写端，读端会如何？s == 0，代表对端关闭
        //         // s == 0: 代表对方关闭,client 退出
        //         logMessage(DEBUG, "client quit -- %s[%d]", clientIp.c_str(), clientPort);
        //         break;
        //     }
        //     else
        //     {
        //         logMessage(DEBUG, "%s[%d] - read: %s", clientIp.c_str(), clientPort, strerror(errno));
        //         break;
        //     }
        // }

        // 只要走到这里，一定是client退出了，服务到此结束
        close(sock); // 如果一个进程对应的文件fd，打开了没有被归还，文件描述符泄漏！
        logMessage(DEBUG, "server close %d done", sock);
    }

private:
    int listensocket_;
    uint16_t port_;
    std::string ip_;
};

static void Usage(std::string proc)
{
    std::cerr << "Usage:\n\t" << proc << " port ip" << std::endl;
    std::cerr << "example:\n\t" << proc << " 8080 127.0.0.1\n"
              << std::endl;
}

// ./ServerTcp local_port local_ip
int main(int argc, char *argv[])
{
    if (argc != 2 && argc != 3)
    {
        Usage(argv[0]);
        exit(7);
    }
    uint16_t port = atoi(argv[1]);
    std::string ip;
    if (argc == 3)
        ip = argv[2];

    TcpServer svr(port, ip);
    svr.init();
    svr.loop();
    return 0;
}